#include "EntryFrameItem.h"
#include "QPainter"
#include "EntryItem.h"
#include "mappingdialog.h"
#include "UnfoldArrayButton.h"
#include "WOPM.h"
#include "DiagramScene.h"
#include "NodeManager.h"
#include "AbstractManager.h"
#include "VariableEntry.h"
#include "Factory_xNodeType.h"
#include "xMappingNode.h"
#include "AbstractPanel.h"
#include "VariablePanel.h"
#include "GraphicsText.h"
#include "NodeOutPort.h"

#include <cassert>

EntryFrameItem::EntryFrameItem( WOP_Entry* entry, std::vector<xMappingNode*> &entryList, DiagramScene* scene, AbstractPanel* panel)
	:PanelTreeItem( entry->getName(), scene->getManager(), panel)
{
	this->_scene = scene;
	this->_wopEntry = entry;
	this->_mpnNode = NULL;
	this->_nodeType = AbstractShapeItem::ENTRY_NODE_FRAME;
	this->_isExpanded = true;

	panel->insertItem(this);

	this->createEntryNodes(entryList);
	// 如果type是array，則會多一個將array展開或是摺疊的按鈕
	if ( _wopEntry->getTypeStr() == "array") {
		_changeTypeButton = new UnfoldArrayButton(this);
		this->setupPort();
		this->setExpanded(false);

		// 如果array第一個element的type是ref，表示array裡面的element都是ref，則顯示unfold button
		// 使用者點unfold button可以展開element type內部的資料結構
		NodeManager* manager= dynamic_cast<NodeManager*>(_manager);
		vector<WOP_Entry*> wopList = manager->getEntry()->getWopList();
		if (wopList.at(0)->getTypeStr()=="ref"){
			this->initUnfoldButton();
		}
		
	}
	this->initName();
}

EntryFrameItem::~EntryFrameItem(void)
{
	
}

void EntryFrameItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget )
{
	// 畫出frame header的底色
	painter->setPen(QPen(Qt::NoPen));
	painter->setBrush(QBrush(QColor("#CACACA")));
	painter->drawRect( 0, 0, this->_width, HEIGHT );

	QImage icon;
	if ( _isExpanded){
		icon = QImage(":/resource/folder_open.png");
	} else {
		icon = QImage(":/resource/folder.png");
	}
	if ( this->_unfoldButton==NULL){
		painter->drawImage(LEFT_PADDING,7,icon);
	} else {
		painter->drawImage(LEFT_PADDING*2,7,icon);
	}
	
	

	// 畫分隔線
	painter->setPen(QPen(QColor("#AAAAAA")));
	painter->drawLine( 0, HEIGHT, this->_width, HEIGHT);
}

QRectF EntryFrameItem::boundingRect() const
{
	return QRectF( 0, 0, this->_width, HEIGHT );
}

void EntryFrameItem::setExpanded( bool expand )
{
	this->_isExpanded = expand;

	// 顯示或隱藏 foreach area
	QPoint pos;
	if ( expand ){
		pos.setX(-100000);
		pos.setY(-100000);
	} else {
		pos.setX(0);
		pos.setY(0);
	}
	MappingDialog *dialog = dynamic_cast<MappingDialog*>(_manager->getMappingDialog());
	assert(dialog);
	dialog->getForeachRect()->setPos(pos);
	unfoldArray(_isExpanded);
}

bool EntryFrameItem::getExpanded()
{
	return this->_isExpanded;
}

void EntryFrameItem::setupPort()
{
	for(int i = 0; i< _mpnNode->getOutportSize(); ++i){
		xOutMappingPort* omp = _mpnNode->getOutPort(i);
		_outportList.push_back(new NodeOutPort(omp,this));
	}

	_outportList.at(0)->setX(this->_width - NodePort::RADIUS);
	_outportList.at(0)->setY(HEIGHT / 2 - NodePort::RADIUS + 1);
}

void EntryFrameItem::createEntryNodes( std::vector<xMappingNode*>& entryList )
{
	using namespace std;
	NodeManager* manager= dynamic_cast<NodeManager*>(_manager);
	assert(manager);

	// 如果type是array的話，先建立一個Generic的entry來代表這個array，並且先將它隱藏起來
	if ( _wopEntry->getTypeStr() == "array") {
		int dimension = dynamic_cast<WOP_Array_Entry*>(_wopEntry)->getDimension();		// 取得array的維度

		// generic entry的名稱會長得像 array_name[i][j].. 這樣
		// 所以取得維度後用 for loop 來建構generic entry名稱，每當i增加1，[]裡面的Ascii也加一
		string name = _name;
		QChar index('i'); 
		for ( int i = 0; i < dimension; ++ i)
		{
			name = name +"[" + QString(QChar(index.toAscii()+i)).toStdString() + "]";
		}

		// 建立 generic entry
		xNodeType* nodeType = Factory_xNodeType::create_xnodetype("wop",_wopEntry);
		nodeType->setName(name);

		xMappingTree *xmt = _scene->getManager()->getMappingTree();
		xMappingNode *genericNode = xmt->create_node(nodeType);
		xmt->add_input_terminal(genericNode);

		this->_mpnNode = genericNode;
		this->setName(name);
	}

	vector<WOP_Entry*> wopList = manager->getEntry()->getWopList();

	for ( int i = 0; i < entryList.size(); ++i )
	{
		EntryItem* entry = manager->createEntryItem( manager->getEntry()->getEntryNameAT(i), manager->getEntry()->getEntryTypeAT(i), entryList.at(i), wopList.at(i));
		manager->getVariablePanel()->insertItem(entry,i+1);
		_entryNodes.push_back(entry);
	}

}

void EntryFrameItem::unfoldArray(bool unfold)
{
	int count = 0;
	this->_outportList.at(0)->setVisible(!unfold);
	this->setForeachElements(!unfold);
	for ( int i = 0; i < _entryNodes.size(); ++i )
	{
		_entryNodes.at(i)->setVisible(unfold);
		_entryNodes.at(i)->setForeachElements(!unfold);
		if ( unfold ){
			count++;
		}
	}

	std::vector<AbstractShapeItem*>::iterator itr;
	for ( itr = _manager->getNodeList().begin(); itr != _manager->getNodeList().end(); ++itr )
	{
		if ( !unfold ){
			if (_manager->isInForEachRect(*itr)){
				(*itr)->getMappingNode()->setForeachElements(true);
			} else {
				(*itr)->getMappingNode()->setForeachElements(false);
			}
		} else {
			(*itr)->getMappingNode()->setForeachElements(false);
		}

	}

	// 當 frame 被 unfold 時，要把 entry 上的 links 清除
	if ( unfold ){
		_entryNodes.at(0)->removeAllLinks();
	} else {
		std::vector<EntryItem*>::iterator itr;
		for ( itr = _entryNodes.begin()+1; itr != _entryNodes.end(); ++itr )
		{
			(*itr)->removeAllLinks();
		}
	}

	int height = ( count * HEIGHT );
	
	//假如展開的高度比 sceneRect 還大，則重設 sceneRect 高度
	//如果是把frame折疊起來而且sceneRect曾經變動過，就將sceneRect高度設回原本的高度
	if ( height > AbstractMappingWindow::SCENE_HEIGHT ){
		//_scene->sceneRect().setHeight(height +100);
		_scene->setSceneRect(0,0,_scene->width(),height +100);
	}
	if ( !unfold && 
		_scene->sceneRect().height() > AbstractMappingWindow::SCENE_HEIGHT){
		_scene->setSceneRect(0,0,_scene->width(),AbstractMappingWindow::SCENE_HEIGHT);
	}

	_scene->update();


}

void EntryFrameItem::remove()
{
	assert(false);
}



void EntryFrameItem::unfold( bool isUnfold)
{
	NodeManager* manager = dynamic_cast<NodeManager*>(_manager);
	if ( isUnfold == true ){
		if ( _children.size() == 0){
			// 當使用者按下unfold按鈕時再建立unfold出來的items
			_children = manager->createUnfoldEntries(_entryNodes[0]->getWOPEntry());

			// 設定unfold items的parent，再將items加入panel中
			std::vector<EntryItem*>::iterator itr;
			int index = _panel->indexOfItem(this) + 1;
			for ( itr = _children.begin(); itr != _children.end(); ++itr )
			{
				(*itr)->setParent(this);
				this->getMappingNode()->addUnfoldChild((*itr)->getMappingNode());
				_panel->insertItem(*itr, index);
				index++;
			}
		} 
		// 如果已經unfold過，直接set visible
		else {
			setChildrenVisible(true);
		}

	} 
	else if ( isUnfold == false ){
		setChildrenVisible(false);
	}
	_panel->updateItemsPosition();
}

void EntryFrameItem::initName()
{
	if ( this->_unfoldButton== NULL){
		_graphicsTextName->setX( 33 );
	} else {
		_graphicsTextName->setX( 44 );
	}
	_graphicsTextName->setAlignment(Qt::AlignLeft);
	
}
